Olaya Hanid - MS BGD
Le plan du projet final Kit Data Science est le suivant :
import requests
import geopandas
import pandas as pd
from bs4 import BeautifulSoup
import os
import urllib
import tempfile
from zipfile import ZipFile
import shutil
import os
from fnmatch import fnmatch
import re
import seaborn as sns
import numpy as np
import plotly.offline as py
import plotly.express as px
import plotly.graph_objects as go
import matplotlib.pyplot as plt
from matplotlib.pyplot import cm
import datetime
from sklearn.linear_model import LinearRegression
import warnings
import unicodedata
from pandas.core.common import SettingWithCopyWarning
warnings.simplefilter(action="ignore", category=SettingWithCopyWarning)
pd.set_option('display.max_columns', None)
py.init_notebook_mode()
url = 'https://www.vendeeglobe.org' url_ranking = 'https://www.vendeeglobe.org/fr/classement' r = requests.get(url_ranking) soup = BeautifulSoup(r.text, 'html.parser') names = [soup.find_all('option')[i]['value']for i in range(1,len(soup.find_all('option')))] for name in names: new_url = url_ranking+"/"+name r = requests.get(new_url) soup = BeautifulSoup(r.text, 'html.parser') if len(soup.find_all('a',{'class':'rankingsdownload'}))!=0 : download_link = soup.find_all('a',{'class':'rankingsdownload'})[0]['href'] final_url = url + download_link r = requests.get(final_url) with open("classement/"+download_link.split('/')[2], 'wb') as f: f.write(r.content)
# Nettoyage des DataFrame de classement
def clean_ranking(filename):
df = pd.read_excel('classement/'+filename, header=[3,4] , index_col=0)
col_name = (('Rang', ''),('Nat. / Voile', ''),('Skipper / Bateau', ''),('Heure FR', ''),('Latitude', ''),('Longitude', ''),
('Depuis 30 minutes', 'Cap'),('Depuis 30 minutes', 'Vitesse / kts'),('Depuis 30 minutes', 'VMG / kts'),
('Depuis 30 minutes', 'Distance / nm'),('Depuis le dernier classement', 'Cap'),('Depuis le dernier classement', 'Vitesse / kts'),
('Depuis le dernier classement', 'VMG / kts'),('Depuis le dernier classement', 'Distance / nm'),('Depuis 24 heures', 'Cap'),('Depuis 24 heures', 'Vitesse / kts'),
('Depuis 24 heures', 'VMG / kts'),('Depuis 24 heures', 'Distance / nm'),('DTF / nm', ''),('DTL / nm', ''))
df.columns = pd.MultiIndex.from_tuples(col_name)
df=df.dropna(axis=1, how="all").dropna(axis=0, how="any")
df.columns = [y[0].split('\n')[0]+y[1].split('\n')[0]
if "Unnamed" not in y[1]
else y[0].split('\n')[0]
for y in df.columns.values]
df['Latitude']=df['Latitude'].apply(lambda x : float(x.split('°')[0]) + float(x.split('°')[1].split("'")[0])/60
if 'N' in x
else (-1)*(float(x.split('°')[0]) + float(x.split('°')[1].split("'")[0])/60))
df['Longitude']=df['Longitude'].apply(lambda x : float(x.split('°')[0]) + float(x.split('°')[1].split("'")[0])/60
if 'E' in x
else (-1)*(float(x.split('°')[0]) + float(x.split('°')[1].split("'")[0])/60))
for i in [3, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]:
df.iloc[:, i] = df.iloc[:, i].apply(lambda x: x.split(' ')[0])
df.iloc[:, i] = df.iloc[:, i].apply(lambda x: x.split('°')[0])
for i in [0, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]:
df.iloc[:, i] = pd.to_numeric(df.iloc[:, i])
df['Skipper'] = df['Skipper / Bateau'].apply(lambda x : x[:x.find('\n')].capitalize())
df['Bateau'] = df['Skipper / Bateau'].apply(lambda x : x[x.find('\n')+1 : ].capitalize())
df["Nat"]=df['Nat. / Voile'].map(lambda x: x[x.find(' ')-3:x.find(' ')])
df["Voile"]=df['Nat. / Voile'].map(lambda x: int(x[1+x.find(' '):]))
df=df.drop(columns=['Nat. / Voile',"Skipper / Bateau"])
date = filename.split('/')[-1].split('_')[1]
df['date'] = f'{date[0:4]}-{date[4:6]}-{date[6:]}'
df['Full_Date'] = pd.to_datetime(df['date'] + ' ' + df['Heure FR'])
df = df.sort_values('Full_Date')
df['Skipper'] = df['Skipper'].apply(lambda x : unicodedata.normalize('NFD', x).encode('ascii', 'ignore').decode("utf-8"))
df['Bateau'] = df['Bateau'].apply(lambda x : unicodedata.normalize('NFD', x).encode('ascii', 'ignore').decode("utf-8"))
return df
df_test = clean_ranking('vendeeglobe_20201109_140000.xlsx')
df_test.head()
| Rang | Heure FR | Latitude | Longitude | Depuis 30 minutesCap | Depuis 30 minutesVitesse / kts | Depuis 30 minutesVMG / kts | Depuis 30 minutesDistance / nm | Depuis le dernier classementCap | Depuis le dernier classementVitesse / kts | Depuis le dernier classementVMG / kts | Depuis le dernier classementDistance / nm | Depuis 24 heuresCap | Depuis 24 heuresVitesse / kts | Depuis 24 heuresVMG / kts | Depuis 24 heuresDistance / nm | DTF / nm | DTL / nm | Skipper | Bateau | Nat | Voile | date | Full_Date | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| NaN | 1 | 14:30 | 45.302500 | -7.597667 | 193 | 10.4 | 10.0 | 5.2 | 194 | 10.2 | 10.0 | 25.5 | 252 | 10.6 | 10.3 | 253.4 | 24070.5 | 0.0 | Damien seguin | Groupe apicil | FRA | 1000 | 2020-11-09 | 2020-11-09 14:30:00 |
| NaN | 31 | 15:00 | 46.472833 | -7.465000 | 208 | 8.8 | 8.7 | 4.4 | 255 | 5.9 | 3.8 | 17.8 | 268 | 9.8 | 5.3 | 236.0 | 24136.4 | 66.0 | Sebastien destremau | Merci | FRA | 69 | 2020-11-09 | 2020-11-09 15:00:00 |
| NaN | 30 | 15:00 | 46.557333 | -7.867167 | 190 | 10.2 | 9.9 | 5.1 | 239 | 5.1 | 4.1 | 15.3 | 269 | 10.6 | 5.5 | 253.2 | 24134.5 | 64.0 | Arnaud boissieres | La mie caline - artisans artipole | FRA | 14 | 2020-11-09 | 2020-11-09 15:00:00 |
| NaN | 29 | 15:00 | 46.376000 | -7.317833 | 190 | 10.1 | 9.8 | 5.1 | 227 | 5.2 | 4.8 | 15.5 | 267 | 9.6 | 5.3 | 230.3 | 24133.5 | 63.1 | Alexia barrier | Tse - 4myplanet | FRA | 72 | 2020-11-09 | 2020-11-09 15:00:00 |
| NaN | 28 | 15:00 | 46.116333 | -6.926833 | 293 | 10.2 | 1.2 | 5.1 | 290 | 9.6 | 2.9 | 28.7 | 263 | 9.0 | 8.3 | 215.7 | 24126.8 | 56.4 | Clement giraud | Compagnie du lit - jiliti | FRA | 83 | 2020-11-09 | 2020-11-09 15:00:00 |
df_rankings = pd.DataFrame()
for x in os.listdir('classement') :
# on recupere que les données jusqu'au 27/01 qui est la date de l'arrivée du premier Skipper
if x < 'vendeeglobe_20210127_140000.xlsx':
df_rankings = df_rankings.append(clean_ranking(x))
df_rankings.head()
| Rang | Heure FR | Latitude | Longitude | Depuis 30 minutesCap | Depuis 30 minutesVitesse / kts | Depuis 30 minutesVMG / kts | Depuis 30 minutesDistance / nm | Depuis le dernier classementCap | Depuis le dernier classementVitesse / kts | Depuis le dernier classementVMG / kts | Depuis le dernier classementDistance / nm | Depuis 24 heuresCap | Depuis 24 heuresVitesse / kts | Depuis 24 heuresVMG / kts | Depuis 24 heuresDistance / nm | DTF / nm | DTL / nm | Skipper | Bateau | Nat | Voile | date | Full_Date | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| NaN | 1 | 09:30 | 43.478667 | -10.523167 | 270 | 9.5 | 3.3 | 4.8 | 255 | 7.5 | 4.5 | 30.1 | 202 | 9.2 | 9.2 | 221.7 | 23921.1 | 0.0 | Jeremie beyou | Charal | FRA | 8 | 2020-11-10 | 2020-11-10 09:30:00 |
| NaN | 31 | 09:30 | 44.843167 | -9.490833 | 183 | 9.6 | 9.1 | 4.8 | 214 | 5.4 | 5.3 | 21.7 | 232 | 6.6 | 5.9 | 158.1 | 24013.5 | 92.4 | Alexia barrier | Tse - 4myplanet | FRA | 72 | 2020-11-10 | 2020-11-10 09:30:00 |
| NaN | 30 | 09:30 | 44.790667 | -10.022333 | 275 | 9.0 | 2.4 | 4.5 | 249 | 5.7 | 3.8 | 22.8 | 226 | 6.0 | 5.5 | 143.9 | 24002.4 | 81.3 | Kojiro shiraishi | Dmg mori global one | JPN | 11 | 2020-11-10 | 2020-11-10 09:30:00 |
| NaN | 29 | 09:30 | 44.348167 | -8.890333 | 270 | 8.0 | 3.1 | 4.0 | 206 | 5.8 | 5.8 | 23.3 | 211 | 6.2 | 6.2 | 149.4 | 23995.5 | 74.5 | Arnaud boissieres | La mie caline - artisans artipole | FRA | 14 | 2020-11-10 | 2020-11-10 09:30:00 |
| NaN | 28 | 09:30 | 44.763167 | -10.830667 | 288 | 11.3 | 0.3 | 5.6 | 282 | 10.6 | 1.7 | 42.5 | 236 | 7.1 | 6.0 | 170.6 | 23988.9 | 67.8 | Giancarlo pedote | Prysmian group | ITA | 34 | 2020-11-10 | 2020-11-10 09:30:00 |
# Extraction des fichies techniques des bateaux
res = requests.get("https://www.vendeeglobe.org/fr/glossaire")
soup = BeautifulSoup(res.content,'html.parser')
fichier_tech = soup.find_all('div', class_ = "sv-u-1 sv-u-s-1-2 sv-u-m-1-3 sv-u-l-1-6")
df_tech = pd.DataFrame(columns= ['Numéro de voile','Anciens noms du bateau','Architecte','Chantier','Date de lancement',
'Longueur','Largeur',"Tirant d'eau",'Déplacement (poids)','Nombre de dérives',
'Hauteur mât','Voile quille','Surface de voiles au près','Surface de voiles au portant'])
for t in fichier_tech:
skipper = t.find('span', class_='boats-list__skipper-name').text
boat = t.find('h3', class_='boats-list__boat-name').text
boat_info = t.find('ul', class_='boats-list__popup-specs-list').text.strip().split('\n')
boat_info_dict = {boat_info[i].split(' : ')[0] : boat_info[i].split(' : ')[1] for i in range(len(boat_info))}
boat_info_dict['Skipper']=skipper.capitalize()
boat_info_dict['Bateau']=boat.capitalize()
df_tech = df_tech.append(boat_info_dict, ignore_index=True)
# Nettoyage du DataFrame correspondant à la fiche technique de chaque bateau
df_tech['Longueur']=df_tech['Longueur'].map(lambda x: float(x[: x.find(' ')].replace(',','.')))
df_tech['Largeur']=df_tech['Largeur'].map(lambda x: float(x[: x.find(' ')].replace(',','.')))
df_tech["Tirant d'eau"]=df_tech["Tirant d'eau"].map(lambda x: float(x[: x.find(' ')].replace(',','.')))
df_tech['Déplacement (poids)']=df_tech['Déplacement (poids)'].map(lambda x: float(x[: x.find(' ')].replace(',','.')) if x!='NC' and x!='nc' else np.nan)
df_tech['Hauteur mât']=df_tech['Hauteur mât'].map(lambda x: float(x[: x.find(' ')].replace(',','.')))
df_tech['Surface de voiles au près']=df_tech['Surface de voiles au près'].map(lambda x: float(x[: x.find(' ')].replace(',','.')))
df_tech['Surface de voiles au portant']=df_tech['Surface de voiles au portant'].map(lambda x: float(x[: x.find(' ')].replace(',','.')))
df_tech['Foil']=df_tech['Nombre de dérives'].apply(lambda x: 1 if x in ['foils', 'foiler'] else 0).astype(int)
df_tech['Skipper'] = df_tech['Skipper'].apply(lambda x : unicodedata.normalize('NFD', x).encode('ascii', 'ignore').decode("utf-8").replace(" "," "))
df_tech['Bateau'] = df_tech['Bateau'].apply(lambda x : unicodedata.normalize('NFD', x).encode('ascii', 'ignore').decode("utf-8"))
df_tech['Skipper'] = df_tech['Skipper'].replace("Sam davies","Samantha davies" )
for i in ['Longueur', 'Largeur', "Tirant d'eau",
'Déplacement (poids)', 'Hauteur mât', 'Surface de voiles au près',
'Surface de voiles au portant', 'Foil']:
df_tech.loc[:, i] = pd.to_numeric(df_tech.loc[:, i])
df_tech.head()
| Numéro de voile | Anciens noms du bateau | Architecte | Chantier | Date de lancement | Longueur | Largeur | Tirant d'eau | Déplacement (poids) | Nombre de dérives | Hauteur mât | Voile quille | Surface de voiles au près | Surface de voiles au portant | Bateau | Skipper | Foil | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | FRA 56 | No Way Back, Vento di Sardegna | VPLP/Verdier | Persico Marine | 01 Août 2015 | 18.28 | 5.85 | 4.5 | 7.0 | foils | 29.0 | monotype | 320.0 | 570.0 | Newrest - art & fenetres | Fabrice amedeo | 1 |
| 1 | FRA 49 | Gitana Eighty, Synerciel, Newrest-Matmut | Bruce Farr Design | Southern Ocean Marine (Nouvelle Zélande) | 08 Mars 2007 | 18.28 | 5.80 | 4.5 | 9.0 | 2 | 28.0 | acier forgé | 280.0 | 560.0 | Pure - best western | Romain attanasio | 0 |
| 2 | FRA72 | Famille Mary-Etamine du Lys, Initiatives Coeur... | Marc Lombard | MAG France | 01 Mars 1998 | 18.28 | 5.54 | 4.5 | 9.0 | 2 | 29.0 | acier | 260.0 | 580.0 | Tse - 4myplanet | Alexia barrier | 0 |
| 3 | 17 | Safran 2 - Des Voiles et Vous | Verdier - VPLP | CDK Technologies | 12 Mars 2015 | 18.28 | 5.80 | 4.5 | 8.0 | foils | 29.0 | acier mécano soudé | 310.0 | 550.0 | Maitre coq iv | Yannick bestaven | 1 |
| 4 | 08 | NaN | VPLP | CDK Technologies | 18 Août 2018 | 18.28 | 5.85 | 4.5 | 8.0 | foils | 29.0 | acier | 320.0 | 600.0 | Charal | Jeremie beyou | 1 |
# DataFrame du dernier fichier excel avec le rang d'arrivée de tous les Skippers
df_final_ranking = pd.read_excel("classement/vendeeglobe_20210305_080000.xlsx", header=[3,4],nrows=30)
df_final_ranking = df_final_ranking.dropna(axis=1, how="all")
df_final_ranking.columns = [y[0].split('\n')[0]+" "+y[1].split('\n')[0]
if "Unnamed" not in y[1]
else y[0].split('\n')[0]
for y in df_final_ranking.columns.values]
df_final_ranking = df_final_ranking[df_final_ranking["Rang"] != "RET"]
df_final_ranking["Rang_arrivée"] = df_final_ranking["Rang"].apply(lambda x: x.split()[0] if x.split()[0] else np.nan).astype(int)
df_final_ranking[["Skipper", "Bateau"]] = df_final_ranking["Skipper / Bateau"].str.split("\n", expand=True)
df_final_ranking['Skipper'] = df_final_ranking['Skipper'].apply(lambda x : unicodedata.normalize('NFD', x).encode('ascii', 'ignore').decode("utf-8").capitalize())
df_final_ranking['Bateau'] = df_final_ranking['Bateau'].apply(lambda x : unicodedata.normalize('NFD', x).encode('ascii', 'ignore').decode("utf-8").capitalize())
df_final_ranking = df_final_ranking.drop(["Nat. / Voile", "Skipper / Bateau", "Rang"],axis=1)
num_cols = ["Sur l'ortho Vitesse", "Sur l'ortho Distance", "Sur le fond Vitesse", "Sur le fond Distance"]
for col in num_cols:
df_final_ranking[col] = df_final_ranking[col].apply(lambda x : x.split(' ')[0])
df_final_ranking[num_cols] = df_final_ranking[num_cols].apply(pd.to_numeric)
df_final_ranking.head()
| Date d'arrivée | Temps de course | Écarts Au premier | Écarts Au précédent | Sur l'ortho Vitesse | Sur l'ortho Distance | ► | Sur le fond Vitesse | Sur le fond Distance | Rang_arrivée | Skipper | Bateau | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 28/01/2021 04:19:46 FR | 80j 03h 44min 46s\n-10h 15min 00s | NaN | NaN | 12.6 | 24365.7 | 117.3 % | 14.8 | 28583.8 | 1 | Yannick bestaven | Maitre coq iv |
| 1 | 27/01/2021 20:35:47 FR | 80j 06h 15min 47s\n | 02h 31min 01s | 02h 31min 01s | 12.6 | 24365.7 | 119.6 % | 15.1 | 29135.0 | 2 | Charlie dalin | Apivia |
| 2 | 28/01/2021 00:45:12 FR | 80j 10h 25min 12s\n | 06h 40min 26s | 04h 09min 25s | 12.6 | 24365.7 | 117.6 % | 14.8 | 28650.0 | 3 | Louis burton | Bureau vallee 2 |
| 3 | 28/01/2021 20:19:55 FR | 80j 13h 44min 55s\n-16h 15min 00s | 10h 00min 09s | 03h 19min 43s | 12.5 | 24365.7 | 112.9 % | 14.1 | 27501.5 | 4 | Jean le cam | Yes we cam ! |
| 4 | 28/01/2021 11:19:45 FR | 80j 14h 59min 45s\n-06h 00min 00s | 11h 14min 59s | 01h 14min 50s | 12.6 | 24365.7 | 116.8 % | 14.7 | 28448.5 | 5 | Boris herrmann | Seaexplorer - yacht club de monaco |
"""DataFrame final : merge le dataframe des classments avec les infos techniques sur le bateau et les informations
concernant l'arrivée du SKipper """
df_all = df_rankings.merge(df_tech, how = 'left', on =['Skipper'])
df_all = df_all.merge(df_final_ranking, how ='left' , on =['Skipper'])
df_all.head()
| Rang | Heure FR | Latitude | Longitude | Depuis 30 minutesCap | Depuis 30 minutesVitesse / kts | Depuis 30 minutesVMG / kts | Depuis 30 minutesDistance / nm | Depuis le dernier classementCap | Depuis le dernier classementVitesse / kts | Depuis le dernier classementVMG / kts | Depuis le dernier classementDistance / nm | Depuis 24 heuresCap | Depuis 24 heuresVitesse / kts | Depuis 24 heuresVMG / kts | Depuis 24 heuresDistance / nm | DTF / nm | DTL / nm | Skipper | Bateau_x | Nat | Voile | date | Full_Date | Numéro de voile | Anciens noms du bateau | Architecte | Chantier | Date de lancement | Longueur | Largeur | Tirant d'eau | Déplacement (poids) | Nombre de dérives | Hauteur mât | Voile quille | Surface de voiles au près | Surface de voiles au portant | Bateau_y | Foil | Date d'arrivée | Temps de course | Écarts Au premier | Écarts Au précédent | Sur l'ortho Vitesse | Sur l'ortho Distance | ► | Sur le fond Vitesse | Sur le fond Distance | Rang_arrivée | Bateau | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 1 | 09:30 | 43.478667 | -10.523167 | 270 | 9.5 | 3.3 | 4.8 | 255 | 7.5 | 4.5 | 30.1 | 202 | 9.2 | 9.2 | 221.7 | 23921.1 | 0.0 | Jeremie beyou | Charal | FRA | 8 | 2020-11-10 | 2020-11-10 09:30:00 | 08 | NaN | VPLP | CDK Technologies | 18 Août 2018 | 18.28 | 5.85 | 4.5 | 8.0 | foils | 29.0 | acier | 320.0 | 600.0 | Charal | 1 | 06/02/2021 09:15:58 FR | 89j 18h 55min 58s\n | 9j 15h 11min 12s | 2j 16h 31min 33s | 11.3 | 24365.7 | 122.0 % | 13.8 | 29728.5 | 13.0 | Charal |
| 1 | 31 | 09:30 | 44.843167 | -9.490833 | 183 | 9.6 | 9.1 | 4.8 | 214 | 5.4 | 5.3 | 21.7 | 232 | 6.6 | 5.9 | 158.1 | 24013.5 | 92.4 | Alexia barrier | Tse - 4myplanet | FRA | 72 | 2020-11-10 | 2020-11-10 09:30:00 | FRA72 | Famille Mary-Etamine du Lys, Initiatives Coeur... | Marc Lombard | MAG France | 01 Mars 1998 | 18.28 | 5.54 | 4.5 | 9.0 | 2 | 29.0 | acier | 260.0 | 580.0 | Tse - 4myplanet | 0 | 28/02/2021 07:23:44 FR | 111j 17h 03min 44s\n | 31j 13h 18min 58s | 7j 22h 48min 04s | 9.1 | 24365.7 | 115.6 % | 10.5 | 28170.7 | 24.0 | Tse - 4myplanet |
| 2 | 30 | 09:30 | 44.790667 | -10.022333 | 275 | 9.0 | 2.4 | 4.5 | 249 | 5.7 | 3.8 | 22.8 | 226 | 6.0 | 5.5 | 143.9 | 24002.4 | 81.3 | Kojiro shiraishi | Dmg mori global one | JPN | 11 | 2020-11-10 | 2020-11-10 09:30:00 | JPN 11 | NaN | VPLP | Multiplast | 05 Septembre 2019 | 18.28 | 5.85 | 4.5 | 8.0 | foils | 29.0 | acier forgé | 320.0 | 580.0 | Dmg mori global one | 1 | 11/02/2021 11:52:56 FR | 94j 21h 32min 56s\n | 14j 17h 48min 10s | 02h 56min 50s | 10.7 | 24365.7 | 119.3 % | 12.8 | 29067.7 | 16.0 | Dmg mori global one |
| 3 | 29 | 09:30 | 44.348167 | -8.890333 | 270 | 8.0 | 3.1 | 4.0 | 206 | 5.8 | 5.8 | 23.3 | 211 | 6.2 | 6.2 | 149.4 | 23995.5 | 74.5 | Arnaud boissieres | La mie caline - artisans artipole | FRA | 14 | 2020-11-10 | 2020-11-10 09:30:00 | FRA 14 | Ecover3, Président, Gamesa, Kilcullen Voyager-... | Owen Clarke Design LLP - Clay Oliver | Hakes Marine - Mer Agitée | 03 Août 2007 | 18.28 | 5.65 | 4.5 | 7.9 | foils | 29.0 | basculante avec vérin | 300.0 | 610.0 | La mie caline - artisans artipole | 1 | 11/02/2021 08:56:06 FR | 94j 18h 36min 06s\n | 14j 14h 51min 20s | 4j 15h 50min 04s | 10.7 | 24365.7 | 116.8 % | 12.5 | 28456.7 | 15.0 | La mie caline - artisans artipole |
| 4 | 28 | 09:30 | 44.763167 | -10.830667 | 288 | 11.3 | 0.3 | 5.6 | 282 | 10.6 | 1.7 | 42.5 | 236 | 7.1 | 6.0 | 170.6 | 23988.9 | 67.8 | Giancarlo pedote | Prysmian group | ITA | 34 | 2020-11-10 | 2020-11-10 09:30:00 | ITA 34 | Saint-Michel - Virbac | VPLP - Verdier | Multiplast | 02 Avril 2015 | 18.28 | 5.80 | 4.5 | 8.0 | foils | 29.0 | acier forgé | 300.0 | 600.0 | Prysmian group | 1 | 28/01/2021 13:02:20 FR | 80j 22h 42min 20s\n | 18h 57min 34s | 44min 00s | 12.5 | 24365.7 | 116.9 % | 14.7 | 28489.9 | 8.0 | Prysmian group |
Dans cette partie, nous allons visualisé les données pour tous les Skippers dans un premier temps et puis pour les top 5 Skippers à la fin de la course pour plus de lisibilité
Dans la figure suivante, nous pouvons visualisé l'evolution du Rang de tout les skippers en même temps (All) ou choisir un Skipper en particulier
di = [dict(label = 'All',
method = 'update',
args = [{'visible': [True*33] }, # the index of True aligns with the indices of plot traces
{'title': 'All',
'showlegend':True}])]
skippers = list(set(df_rankings['Skipper']))
for z in skippers :
k = [False]*33
k[skippers.index(z)] = True
di.append(dict(label = z ,
method = 'update',
args = [{'visible': k }, # the index of True aligns with the indices of plot traces
{'title': z,
'showlegend':True}]))
fig = go.Figure()
for z in df_rankings.Skipper.unique():
data = df_rankings[df_rankings['Skipper'] == z]
data = data.sort_values(by=['Full_Date'])
fig.add_trace(go.Scatter(x = data.Full_Date ,
y = data.Rang ,mode = 'lines+markers' , name = z ))
fig.update_layout(width=1000,
height=500,
updatemenus=[go.layout.Updatemenu(
active=0,
buttons=list(di)
)])
fig.update_layout(title_text="Évolution du Rang")
di = [dict(label = 'All',
method = 'update',
args = [{'visible': [True*33] }, # the index of True aligns with the indices of plot traces
{'title': 'All',
'showlegend':True}])]
skippers = list(set(df_rankings['Skipper']))
for z in skippers :
k = [False]*33
k[skippers.index(z)] = True
di.append(dict(label = z ,
method = 'update',
args = [{'visible': k }, # the index of True aligns with the indices of plot traces
{'title': z,
'showlegend':True}]))
fig = go.Figure()
for z in df_rankings.Skipper.unique():
data = df_rankings[df_rankings['Skipper'] == z]
data = data.sort_values(by=['Full_Date'])
fig.add_trace(go.Scatter(x = data.Full_Date ,
y = data["Depuis le dernier classementVitesse / kts"] ,mode = 'lines' , name = z ))
fig.update_layout(width=1000,
height=500,
updatemenus=[go.layout.Updatemenu(
active=0,
buttons=list(di)
)])
fig.update_layout(title_text="Évolution de la vitesse moyenne pour chaque skipper")
head_skippers = df_final_ranking['Skipper'][:5]
di = [dict(label = 'All',
method = 'update',
args = [{'visible': [True*33] }, # the index of True aligns with the indices of plot traces
{'title': 'All',
'showlegend':True}])]
skippers = list(head_skippers)
for z in head_skippers :
k = [False]*5
k[skippers.index(z)] = True
di.append(dict(label = z ,
method = 'update',
args = [{'visible': k }, # the index of True aligns with the indices of plot traces
{'title': z,
'showlegend':True}]))
fig = go.Figure()
for z in skippers:
z = z.capitalize()
data = df_rankings[df_rankings['Skipper'] == z]
data = data.sort_values(by=['Full_Date'])
fig.add_trace(go.Scatter(x = data.Full_Date ,
y = data["Depuis le dernier classementVitesse / kts"] ,mode = 'lines' , name = z ))
fig.update_layout(width=1000,
height=500,
updatemenus=[go.layout.Updatemenu(
active=0,
buttons=list(di)
)])
fig.update_layout(title_text="Nombre de courses ASAP par région")
fig, ax = plt.subplots(figsize=(20,10))
geopandas.read_file(geopandas.datasets.get_path('naturalearth_lowres')).plot(ax=ax)
gdf = geopandas.GeoDataFrame(
df_rankings, geometry=geopandas.points_from_xy(df_rankings.Longitude, df_rankings.Latitude))
gdf.plot(column = 'Skipper', ax=ax, alpha=0.25, cmap= 'Paired', legend = True)
plt.title('Trajet des top5 skippers')
plt.show()
fig, ax = plt.subplots(figsize=(20,10))
geopandas.read_file(geopandas.datasets.get_path('naturalearth_lowres')).plot(ax=ax)
temp = df_rankings.loc[(df_rankings['Skipper'].isin(head_skippers))]
gdf = geopandas.GeoDataFrame(
temp, geometry=geopandas.points_from_xy(temp.Longitude, temp.Latitude))
gdf.plot(column = 'Skipper', ax=ax, alpha=0.25, cmap= 'tab20b', legend = True)
plt.title('Trajet des top5 skippers')
plt.show()
temp = df_rankings[['Skipper', 'Full_Date', 'Depuis le dernier classementDistance / nm']].groupby(['Skipper', 'Full_Date']).agg({'Depuis le dernier classementDistance / nm':'sum'})
plt.figure(figsize=(15,8))
for sk in set(df_rankings['Skipper']):
plt.plot(temp.loc[sk].index, temp.loc[sk].cumsum(), label = sk)
plt.xlabel('Date')
plt.ylabel('Distance')
plt.title('Distance cumulée parcourue par Skipper')
plt.legend(loc='upper left')
plt.show()
plt.figure(figsize=(15,7))
for head_sk in head_skippers:
plt.plot(temp.loc[head_sk].index, temp.loc[head_sk].cumsum(), label = head_sk)
plt.xlabel('Date')
plt.ylabel('Distance')
plt.title('Distance cumulée parcourue par Skipper')
plt.legend(loc='upper left')
plt.show()
df_all.groupby(['Skipper'])['Rang'].mean().sort_values().to_frame("Rang moyen").reset_index().merge(df_final_ranking[['Skipper','Rang_arrivée']], how='left', on = 'Skipper').head()
| Skipper | Rang moyen | Rang_arrivée | |
|---|---|---|---|
| 0 | Charlie dalin | 2.286611 | 2.0 |
| 1 | Thomas ruyant | 3.519833 | 6.0 |
| 2 | Yannick bestaven | 4.346555 | 1.0 |
| 3 | Jean le cam | 5.574113 | 4.0 |
| 4 | Kevin escoffier | 5.807407 | NaN |
Nous remarquons que le rang moyen ne reflète pas le rang final d'arrivée; par exemple Yannick avait un rang moyen de 4.34 mais a fini premier au final
df_all.groupby(["Skipper","Rang_arrivée"])["Depuis le dernier classementVMG / kts"].mean().sort_values(ascending=False).to_frame().head()
| Depuis le dernier classementVMG / kts | ||
|---|---|---|
| Skipper | Rang_arrivée | |
| Louis burton | 3.0 | 12.805010 |
| Charlie dalin | 2.0 | 12.771130 |
| Boris herrmann | 5.0 | 12.765344 |
| Yannick bestaven | 1.0 | 12.679123 |
| Giancarlo pedote | 8.0 | 12.622756 |
df_all.groupby(["Skipper","Rang_arrivée"])["Depuis le dernier classementVitesse / kts"].mean().sort_values(ascending=False).to_frame().head()
| Depuis le dernier classementVitesse / kts | ||
|---|---|---|
| Skipper | Rang_arrivée | |
| Charlie dalin | 2.0 | 14.685774 |
| Thomas ruyant | 6.0 | 14.580167 |
| Louis burton | 3.0 | 14.578288 |
| Boris herrmann | 5.0 | 14.443424 |
| Yannick bestaven | 1.0 | 14.394154 |
Nous remarquons que les Skippers ayant une vitesste moyenne élevée sont parmis les premiers arrivés à la fin de la course
sns.pairplot(df_all[['Depuis le dernier classementVitesse / kts', 'Depuis le dernier classementVMG / kts', 'Rang', "Depuis le dernier classementDistance / nm"]])
<seaborn.axisgrid.PairGrid at 0x7f925cf4bf40>
df_all.groupby("Foil")["Rang"].mean().to_frame()
| Rang | |
|---|---|
| Foil | |
| 0 | 17.432400 |
| 1 | 12.372687 |
df_all.groupby("Foil")["Rang_arrivée"].mean().to_frame()
| Rang_arrivée | |
|---|---|
| Foil | |
| 0 | 16.153846 |
| 1 | 9.582768 |
Les Skippers avec des foils sont mieux classés
df_all.groupby("Foil")["Depuis le dernier classementVitesse / kts"].mean().to_frame()
| Depuis le dernier classementVitesse / kts | |
|---|---|
| Foil | |
| 0 | 12.228606 |
| 1 | 13.563750 |
df_all.groupby("Foil")["Depuis le dernier classementVMG / kts"].mean().to_frame()
| Depuis le dernier classementVMG / kts | |
|---|---|
| Foil | |
| 0 | 10.922824 |
| 1 | 11.842648 |
Les SKippers avec des foils ont une vitesse moyenne plus elévée
Le but de cette partie est de prédire le prochain classement à partir du dernier classement de chaque Skipper ainsi que d'autres features
df = df_all.drop([ "Nat", "Voile", "Bateau_x", "Bateau_y", "Date d'arrivée", "Temps de course", "Écarts Au précédent","Rang_arrivée",
'Numéro de voile', 'Anciens noms du bateau', 'Architecte', 'Chantier',"Écarts Au premier","►", "Bateau", "Sur l'ortho Vitesse", "Sur l'ortho Distance",
"Sur le fond Vitesse", "Sur le fond Distance",'Date de lancement', "Heure FR", "date", "Nombre de dérives", "Voile quille", "Déplacement (poids)"], axis = 1)
df = df.sort_values(['Skipper',"Full_Date"])
df_train = df[df["Full_Date"]<pd.to_datetime('2021-01-01')]
df_test = df[df["Full_Date"]>=pd.to_datetime('2021-01-01')]
X_train = df_train.drop(["Full_Date","Skipper","Rang"], axis = 1)
y_train = df_train['Rang']
X_test = df_test.drop(["Full_Date","Skipper","Rang"], axis = 1)
y_test = df_test['Rang']
regr = LinearRegression()
regr.fit(X_train, y_train)
regr.score(X_train, y_train)
0.7544791121449909
regr.coef_
array([ 1.07996032e-01, -6.34241533e-03, -1.46937744e-03, -4.39153254e-02,
1.08812226e-01, -2.37288658e-01, -1.67098179e-03, -2.01249587e-02,
-5.93525790e-02, -1.53932079e-03, 7.49676954e-03, 6.87302074e-01,
-1.93019332e-01, -2.74767787e-02, 8.18611921e-05, 5.17414676e-03,
5.93969318e-15, -1.97191639e+00, -8.88178420e-16, 4.21410575e-01,
-2.44149327e-02, 1.95962712e-03, -6.85825130e-01])
À partir des coefficients de la regression, nous remarquons par exemple que les variables 'Longueur' et "Tirant d'eau" ont un faible coefficient et donc n'ont pas une grande importance dans la prédiction du rang